package retry;

import io.github.itning.retry.Attempt;
import io.github.itning.retry.RetryException;
import io.github.itning.retry.Retryer;
import io.github.itning.retry.RetryerBuilder;
import io.github.itning.retry.listener.RetryListener;
import io.github.itning.retry.strategy.block.BlockStrategies;
import io.github.itning.retry.strategy.limit.AttemptTimeLimiters;
import io.github.itning.retry.strategy.stop.StopStrategies;
import io.github.itning.retry.strategy.wait.WaitStrategies;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.lang.math.RandomUtils;
import org.springframework.remoting.RemoteAccessException;

import java.util.concurrent.Executors;
import java.util.concurrent.TimeUnit;

/**
 * @author dushougudu
 */
@Slf4j
public class RetryDemoTask {
    /**
     * 重试方法
     *
     * @return
     */
    public static boolean retryTask(String param) {
        log.info("收到请求参数:{}", param);
        int i = RandomUtils.nextInt(11);
        log.info("随机生成的数:{}", i);
        if (i < 2) {
            log.info("为0,抛出参数异常.");
            throw new IllegalArgumentException("参数异常");
        } else if (i < 5) {
            log.info("为1,返回true.");
            return true;
        } else if (i < 7) {
            log.info("为2,返回false.");
            return false;
        } else {
            //为其他
            log.info("大于2,抛出自定义异常.");
            throw new RemoteAccessException("大于2,抛出自定义异常");
        }
    }

    public static void main(String[] args) {
        // RetryerBuilder 构建重试实例 retryer,可以设置重试源且可以支持多个重试源，可以配置重试次数或重试超时时间，以及可以配置等待时间间隔
        Retryer<Boolean> retryer = RetryerBuilder.<Boolean>newBuilder()
                //设置异常重试源
                .retryIfExceptionOfType(RemoteAccessException.class)
                //设置根据结果重试
                .retryIfResult(res -> res == false)
                //设置等待间隔时间
                .withWaitStrategy(WaitStrategies.fixedWait(3, TimeUnit.SECONDS))
                //设置最大重试次数
                .withStopStrategy(StopStrategies.stopAfterAttempt(3))
                //设置重试阻塞策略
                .withBlockStrategy(BlockStrategies.threadSleepStrategy())
                //设置单次任务执行时间限制
                .withAttemptTimeLimiter(AttemptTimeLimiters.fixedTimeLimit(3, TimeUnit.SECONDS, Executors.newSingleThreadExecutor()))
                //设置重试监听器
                .withRetryListener(new RetryListener() {
                    @Override
                    public <V> void onRetry(Attempt<V> attempt) {
                        log.error("第【{}】次调用失败", attempt.getAttemptNumber());
                    }
                })
                .build();
        Boolean b = null;
        try {
            b = retryer.call(() -> RetryDemoTask.retryTask("abc"));
        } catch (RetryException e) {
            if (e.getLastFailedAttempt().hasResult()) {
                Attempt<Boolean> lastAttempt = (Attempt<Boolean>) e.getLastFailedAttempt();
                b = lastAttempt.getResult();
            }
        } catch (Exception e) {
            e.printStackTrace();
        }
        System.out.println(b);
    }

}
